﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;

namespace SmartMathLibrary
{
    /// <summary>
    /// This class provides the paring of a matrix in string form.
    /// </summary>
    [Serializable]
    public class MatrixParser
    {
        /// <summary>
        /// The value to parse.
        /// </summary>
        private String parseValue;

        /// <summary>
        /// The element seperator.
        /// </summary>
        private char elementSeparator;

        /// <summary>
        /// The numberstyle formation.
        /// </summary>
        private NumberStyles numberStyle;

        /// <summary>
        /// The numberformat information formation.
        /// </summary>
        private NumberFormatInfo numberFormatInfo;

        /// <summary>
        /// Initializes a new instance of the <see cref="MatrixParser"/> class.
        /// </summary>
        /// <param name="parseValue">The string value to parse.</param>
        /// <param name="elementSeparator">The element separator.</param>
        /// <param name="numberStyle">The number style.</param>
        /// <param name="numberFormatInfo">The number format info.</param>
        public MatrixParser(String parseValue, char elementSeparator, NumberStyles numberStyle,
                            NumberFormatInfo numberFormatInfo)
        {
            this.parseValue = parseValue;
            this.numberStyle = numberStyle;
            this.numberFormatInfo = numberFormatInfo;
            this.elementSeparator = elementSeparator;
        }

        /// <summary>
        /// Gets or sets the string value to parse.
        /// </summary>
        /// <value>The string value to parse.</value>
        public string ParseValue
        {
            get { return parseValue; }
            set { parseValue = value; }
        }

        /// <summary>
        /// Gets or sets the element separator of the string value to parse.
        /// </summary>
        /// <value>The element separator of the string value to parse.</value>
        public char ElementSeparator
        {
            get { return elementSeparator; }
            set { elementSeparator = value; }
        }

        /// <summary>
        /// Gets or sets the number style of the string value to parse.
        /// </summary>
        /// <value>The number style of the string value to parse.</value>
        public NumberStyles NumberStyle
        {
            get { return numberStyle; }
            set { numberStyle = value; }
        }

        /// <summary>
        /// Gets or sets the number format information of the string value to parse.
        /// </summary>
        /// <value>The number format information of the string value to parse.</value>
        public NumberFormatInfo NumberFormatInfo
        {
            get { return numberFormatInfo; }
            set { numberFormatInfo = value; }
        }

        /// <summary>
        /// Parses the matrix out of the string value to parse.
        /// </summary>
        /// <returns>The parsed matrix.</returns>
        public Matrix Parse()
        {
            String[] lines = this.parseValue.Split(new char[] {'\n'},
                                                   StringSplitOptions.RemoveEmptyEntries);

            if (lines.Length == 0)
            {
                return new Matrix(0, 0);
            }

            int rows = lines.Length;
            int columns =
                lines[0].Split(new char[] {this.elementSeparator}, StringSplitOptions.RemoveEmptyEntries).Length;
            Matrix result = new Matrix(rows, columns);

            for (int i = 0; i < lines.Length; i++)
            {
                String[] columnValues = lines[i].Split(new char[] {this.elementSeparator},
                                                       StringSplitOptions.RemoveEmptyEntries);

                if (columnValues.Length != columns)
                {
                    throw new ParserException("Cannot find the correct number of expected columns.");
                }

                for (int j = 0; j < columnValues.Length; j++)
                {
                    result.SetValueAtPosition(i, j,
                                              Double.Parse(columnValues[j].Trim(), this.numberStyle,
                                                           this.numberFormatInfo));
                }
            }

            return result;
        }
    }
}